<?php
/**
 * Application bootstrap, old-school PHP style
 *
 * @author    Mon Zafra <monzee at gmail>
 * @copyright (c)2009 Mon Zafra
 * @category  Mz
 * @package   demo
 * @license   http://mz-project.googlecode.com/svn/trunk/LICENSE     MIT License
 * @version   SVN: $Id: bootstrap.php 11 2009-02-28 13:37:10Z monzee $
 */

// env constants
define('ENV_DEVELOPMENT', 'dev');
define('ENV_TESTING', 'test');
define('ENV_PRODUCTION', 'production');
define('ENV_DEBUG', 'debug');

// set this to your timezone
date_default_timezone_set('Asia/Manila');

// build new include path
$old_paths = explode(PATH_SEPARATOR, get_include_path());
$paths_to_prepend = array(path_to('../lib'));
$paths_to_append = array(path_to('models'));
$merged = array_merge($paths_to_prepend, $old_paths, $paths_to_append);
$new_paths = array_map('realpath', array_unique($merged));

set_include_path(implode(PATH_SEPARATOR, $new_paths));

// autoload classes
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

/*
 * main() ENDS HERE :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: ::
 */

/**
 * Sets environment settings, registers bootstrapper plugin.
 *
 * @staticvar bool $initialized Has this function been called already?
 * @param bool $reinitialize Initialize again for some reason?
 * @return void
 */
function init($reinitialize = false)
{
    static $initialized = false;

    if ($initialized && !$reinitialize) {
        return;
    }

    $env = environment();
    if (ENV_PRODUCTION == $env) {
        error_reporting(0);
        ini_set('display_errors', 0);
    } else {
        error_reporting(E_ALL|E_STRICT);
        ini_set('display_errors', 1);
    }

    $functions = array('setup_routes', 'setup_database', 'setup_controllers',
        'setup_view', 'setup_plugins');

    front()->throwExceptions(ENV_PRODUCTION != $env)
           ->registerPlugin(new Mz_Bootstrapper($functions));

    $initialized = true;
}

/**
 * Set named routes here.
 */
function setup_routes()
{

}

/**
 * Set default Zend_Db_Table adapter here.
 *
 * @param bool $reset Set the default adapter even if it's already set?
 */
function setup_database($reset = false)
{
    if ($reset || null === Zend_Db_Table_Abstract::getDefaultAdapter()) {
        $db_conf = config(environment())->db->toArray();
        $driver = array_shift($db_conf);
        $params = array_shift($db_conf);

        $adapter = Zend_Db::factory($driver, $params);
        Zend_Db_Table_Abstract::setDefaultAdapter($adapter);
    }
}

/**
 * Set controller directory, register modules, action helpers and paths here.
 */
function setup_controllers()
{
    front()->setControllerDirectory(path_to('controllers'))
           ->addModuleDirectory(path_to('modules'));

    Zend_Controller_Action_HelperBroker::addPath(
        path_to('controllers/helpers'), 'Action');

    // i had problems with _redirect() prepending the base url twice without the
    // the following line. i'm not sure if this is the proper solution.
    Zend_Controller_Action_HelperBroker::getStaticHelper('Redirector')
        ->setPrependBase(false);
}

/**
 * Setup ViewRenderer, Layout, and View, register view helper paths here.
 */
function setup_view()
{
    $view = new Zend_View();
    $view->addHelperPath(path_to('views/helpers'), 'View')
         ->doctype(Zend_View_Helper_Doctype::XHTML1_TRANSITIONAL);

    $renderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
    /* @var $renderer Zend_Controller_Action_Helper_ViewRenderer */
    $renderer->setView($view);

    Zend_Layout::startMvc(array('layoutPath' => path_to('layouts')));
}

/**
 * Register plugins
 */
function setup_plugins()
{
    // true == autodiscover modules with preRoute() methods from the currently
    // defined module directory. this is _not_ ideal. see the notes in the
    // comments for the method Mz_Module_Initializer::autoDiscover()
    Mz_Module_Initializer::startMvc(true);
}

/*
 * UTILITY FUNCTIONS :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: ::
 */

/**
 * Gets or sets the front controller.
 *
 * @param mixed $set_to Front controller instance to store. If null, uses
 *              Zend_Controller_Front singleton
 * @return Zend_Controller_Front
 */
function front($set_to = null)
{
    static $front;
    if (null !== $set_to) {
        $front = $set_to;
    } else if (null === $front) {
        $front = Zend_Controller_Front::getInstance();
    }

    return $front;
}

/**
 * Loads config, returns a value from the loaded config.
 *
 * @staticvar Zend_Config $config Stored Zend_Config object
 * @param string             $key    Key to get, null to get the whole config
 * @param string|Zend_Config $file   Config file name or Zend_Config instance
 * @param bool               $reload Reload file or overwrite stored config?
 * @return mixed
 */
function config($key = null, $file = 'config.ini', $reload = false)
{
    static $config;
    if (null === $config || $reload) {
        if ($file instanceof Zend_Config) {
            $config = $file;
        } else {
            $file = path_to($file);
            $config = new Zend_Config_Ini($file);
        }
    }

    if (null === $key) {
        return $config;
    } else {
        return $config->$key;
    }
}

/**
 * Returns a path/file relative to the path of the bootstrap.
 *
 * @staticvar string $base_path Path where the bootstrap is
 * @param string $file
 * @return string
 */
function path_to($file = null)
{
    static $base_path;
    if (empty($base_path)) {
        $base_path = realpath(dirname(__FILE__));
    }

    $ret = $base_path;
    if (!empty($file)) {
        $file = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, trim($file, '/\\'));
        $ret .= DIRECTORY_SEPARATOR . $file;
    }

    return $ret;
}

/**
 * Gets or sets the application environment.
 *
 * @staticvar string $env
 * @param string $setting
 * @return string
 */
function environment($setting = null)
{
    static $env = ENV_DEVELOPMENT;
    if (null !== $setting) {
        $env = $setting;
    }

    return $env;
}

/**
 * Sets the environment, registers bootstrap functions and dispatches
 * the front controller.
 *
 * @return mixed
 */
function run($env = ENV_DEVELOPMENT)
{
    environment($env);
    init();
    return front()->dispatch();
}
